////////////////////////////////////////////////////////////////////////////////
//File:					TestCubeApplication.cpp
//Author:				Kesitem
//This file is part of UglyProject.
//See UglyProject.txt for copyright informations.
////////////////////////////////////////////////////////////////////////////////
#include "TestCubeApplication.h"

#define BUFFER_OFFSET(i) ((char*)NULL+(i))

/**
 * \brief Constructor.
 */
TestCubeApplication::TestCubeApplication()
{
}


/**
 * \brief Init the application.
 *
 * \return False if error.
 */
bool TestCubeApplication::init()
{
    //Vertex of the cube
    static const GLfloat vertexData[] =
    {
        //Left side
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,

        //Back side
        1.0f, 1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f, 1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,

        //Bottom side
        1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,

        //Front side
        -1.0f, 1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,

        //Right side
        1.0f, 1.0f, 1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f,-1.0f,
        1.0f,-1.0f,-1.0f,
        1.0f, 1.0f, 1.0f,
        1.0f,-1.0f, 1.0f,

        //Top side
        1.0f, 1.0f, 1.0f,
        1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
        1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f
    };

    //Create vertex buffer
    mVertexBuffer.create(GL_ARRAY_BUFFER, GL_STATIC_DRAW);
    mVertexBuffer.setData(sizeof(vertexData), vertexData);

    //Color of the cube
    static const GLfloat colorData[] =
    {
        //Left side
        0.0f,  1.0f,  0.0f,
        0.0f,  1.0f,  0.0f,
        0.0f,  1.0f,  0.0f,
        0.0f,  1.0f,  0.0f,
        0.0f,  1.0f,  0.0f,
        0.0f,  1.0f,  0.0f,

        //Back side
        1.0f,  1.0f,  0.0f,
        1.0f,  1.0f,  0.0f,
        1.0f,  1.0f,  0.0f,
        1.0f,  1.0f,  0.0f,
        1.0f,  1.0f,  0.0f,
        1.0f,  1.0f,  0.0f,

        //Bottom side
        0.0f,  1.0f,  1.0f,
        0.0f,  1.0f,  1.0f,
        0.0f,  1.0f,  1.0f,
        0.0f,  1.0f,  1.0f,
        0.0f,  1.0f,  1.0f,
        0.0f,  1.0f,  1.0f,

        //Front side
        0.0f,  0.0f,  1.0f,
        0.0f,  0.0f,  1.0f,
        0.0f,  0.0f,  1.0f,
        0.0f,  0.0f,  1.0f,
        0.0f,  0.0f,  1.0f,
        0.0f,  0.0f,  1.0f,

        //Right side
        1.0f,  0.0f,  1.0f,
        1.0f,  0.0f,  1.0f,
        1.0f,  0.0f,  1.0f,
        1.0f,  0.0f,  1.0f,
        1.0f,  0.0f,  1.0f,
        1.0f,  0.0f,  1.0f,

        //Top side
        1.0f,  0.0f,  0.0f,
        1.0f,  0.0f,  0.0f,
        1.0f,  0.0f,  0.0f,
        1.0f,  0.0f,  0.0f,
        1.0f,  0.0f,  0.0f,
        1.0f,  0.0f,  0.0f
    };

    //Create color buffer
    mColorBuffer.create(GL_ARRAY_BUFFER, GL_STATIC_DRAW);
    mColorBuffer.setData(sizeof(colorData), colorData);

    //Create progam
    mProgram.create("./data/shader/basic-fixed.vert", "./data/shader/basic-fixed.frag");
    mProgram.bindAttrib(0, "aVertex");
    mProgram.bindAttrib(1, "aColor");
    mProgram.linkProgram();

    //Set clear color
    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
    //Enable depth test
    glEnable(GL_DEPTH_TEST);
    //Accept fragment if it closer to the camera than the former one
    glDepthFunc(GL_LESS);

    return true;
}


/**
 * \brief Shutdown the application.
 */
void TestCubeApplication::shutdown()
{
}


/**
 * \brief Update the application.
 *
 * \return False if error.
 */
bool TestCubeApplication::update()
{
    //Create projection matrix
    glm::mat4 projectionMatrix = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);

    //Or, create an ortho camera :
    //glm::mat4 projectionMatrix = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); // In world coordinates

    // Camera matrix
    glm::mat4 viewMatrix = glm::lookAt(
                                 glm::vec3(4,3,-3), // Camera is at (4,3,3), in World Space
                                 glm::vec3(0,0,0), // and looks at the origin
                                 glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down)
                                 );

    // Model matrix : an identity matrix (model will be at the origin)
    glm::mat4 modelMatrix = glm::mat4(1.0f);
    // Our ModelViewProjection : multiplication of our 3 matrices
    glm::mat4 mvpMatrix = projectionMatrix * viewMatrix * modelMatrix; // Remember, matrix multiplication is the other way around


    //Clear the color and the depth
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //Activate program to use
    mProgram.useProgram();

    //Send mvp matrix to shader
    mProgram.sendUniform("uMVPMatrix", glm::value_ptr(mvpMatrix));

    //Set vertices
    glEnableVertexAttribArray(0);
    mVertexBuffer.bind();
    glVertexAttribPointer(
       0,                  // Vertex are attribute 0
       3,                  // Size
       GL_FLOAT,           // Type
       GL_FALSE,           // normalized?
       0,                  // stride
       (void*)0            // array buffer offset
    );

    //Set colors
    glEnableVertexAttribArray(1);
    mColorBuffer.bind();
    glVertexAttribPointer(
       1,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
       3,                  // size
       GL_FLOAT,           // type
       GL_FALSE,           // normalized?
       0,                  // stride
       (void*)0            // array buffer offset
    );

    //Draw the triangle !
    glDrawArrays(GL_TRIANGLES, 0, 36);

    //Disable attributes
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

    return true;
}
